;<FOONEX>DSKPAK.MAC;3 18-Feb-81 22:16:38, Edit by PETERS
;FIX DERROR TO NOT CLOBBER STACK - WE NOW "JSP A,DERROR" LIKE DSKERR
;<FOONEX>DSKPAK.MAC;2 17-Feb-81 21:25:08, Edit by PETERS
;REMOVE TEST FOR NOT READY STATUS AT DOOP
;DSK:<FOONEX>DSKPAK.CDC;5 28-Jul-80 16:19:51, Edit by FRENCH
;MAKE RETRY 1000. TIMES AGAIN
;DSK:<FOONEX>DSKPAK.CDC;4 23-Jul-80 15:21:52, Edit by FRENCH
;MORE BAT QUEUEING STUFF, ALLOW JSYS INTERFACE ETC. (PIOFF LOCK BATENQ)
;DSK:<PEFMON>DSKPAK.CDC;26 20-Jun-80 12:18:43, Edit by FRENCH
;ADD BAT LOGGING FLAGS AND PROCESSING
;DSK:<PEFMON>DSKPAK.CDC;21 18-Jun-80 12:10:24, Edit by FRENCH
;REDEFINE DSKUER FOR NO CONFLICT WITH DSKUOP
;DSK:<PEFMON>DSKPAK.CDC;20 16-Jun-80 11:41:09, Edit by FRENCH
;ON ERROR, UDSKIO GETS RETURNED STATUS BITS IN 1
;SPLIT UDSKIO Q TABLES AND ADD RETURNED STATUS TABLE
;DSK:<PEFMON>DSKPAK.CDC;8 12-Jun-80 17:50:26, Edit by FRENCH
;START SWAP ERROR RECOVERY LOGIC
;DSK:<PEFMON>DSKPAK.CDC;5 12-Jun-80 15:01:54, Edit by FRENCH
;CHANGE RETRY COUNTER FROM 1000 TO 5, OFF AMPEXES NOW
;DSK:<PEFMON>DSKPAK.CDC;2 12-Jun-80 12:17:29, Edit by FRENCH
;ADDED UDSKIO ERROR BIT DSKUER
;DSK:<PEFMON>DSKPAK.CDC;32 27-May-80 11:25:30, Edit by FRENCH
;DON'T JUMP TO DERROR FROM WRONG PLACES, ADDED DSKERR
;<PEFMON>DSKPAK.CDC;30    23-May-80 17:38:26    EDIT BY FRENCH
;TEST B6,9,10 FOR DETERMINATION OF BAD SPOT FOR NOW.
;REMOVE TEST OF BSPOTS IN EFANCY
;DSK:<PEFMON>DSKPAK.CDC;23 14-May-80 16:55:27, Edit by FRENCH
;REDID DSKPAR
;DSK:<PEFMON>DSKPAK.CDC;13 28-Apr-80 13:01:15, Edit by FRENCH
;ADDED AUTO BAT BLK QUEUER AND LOGGER
;DSK:<PEFMON>DSKPAK.F3A;13 17-Apr-80 17:10:17, Edit by FRENCH
;RENAME TO DSKPAK.CDC
;DSK:<PEFMON>DSKPAK.F3A;12 17-Apr-80 13:41:52, Edit by FRENCH
;ADDED FILIFG
;DSK:<PEFMON>DSKPAK.F3A;11 15-Apr-80 17:17:40, Edit by FRENCH
;MADE NSECTK INTERNAL
;DSK:<PEFWRK>DSKPAK.F3A;6 11-Apr-80 14:31:15, Edit by FRENCH
;MAKE DREAD AND DWRITE INTERNAL
;DSK:<PEFWRK>DSKPAK.F3A;5 10-Apr-80 13:26:53, Edit by FRENCH
;REMOVED CDDSCA, CHANGED MY MIND ABOUT CRASH DUMP XB ADRSING
;DSK:<PEFWRK>DSKPAK.F3A;7  3-Apr-80 20:00:48, Edit by FRENCH
;MOVED CVDSK AND CDSKVA FROM HERE TO DSK.MAC
;DSK:<PEFWRK>DSKPAK.F3A;6  2-Apr-80 16:01:00, Edit by FRENCH
;MOVED NUNTBT,NCYLBT,NSRFBT,NSECBT TO PARAMS
;DSK:<PEFWRK>DSKPAK.F3A;4 28-Mar-80 15:22:49, Edit by FRENCH
;MOVE CVSWAD AND CVSWAD FROM HERE TO DSK.MAC
;DSK:<PEFWRK>DSKPAK.F3A;3 28-Mar-80 15:00:45, Edit by FRENCH
;ADDED CVADSW ROUTINE
;DSK:<PEFWRK>DSKPAK.F3A;1 26-Mar-80 17:01:44, Edit by FRENCH
;ADDED CDDSCA AND FDDSCA
;<134-TENEX>DSKPAK.F3A;10    26-Jan-80 22:14:41    EDIT BY PETERS
; Try one thousand times before DERROR, turn off compare flags
;<134-TENEX>DSKPAK.F3A;9     6-Jan-80 18:07:11    EDIT BY PETERS
; Moved NTKUN, NSURFS, NSECS, and NWSEC to PARAMS
;<134-TENEX>DSKPAK.F3A;8     2-Sep-79 20:40:51    EDIT BY PETERS
;<134-TENEX>DSKPAK.F3A;7     2-Sep-79 18:07:21    EDIT BY PETERS
;<134-TENEX>DSKPAK.F3A;6     2-Sep-79 18:02:54    EDIT BY PETERS
;<134-TENEX>DSKPAK.F3A;5     2-Sep-79 17:38:59    EDIT BY PETERS
;<134-TENEX>DSKPAK.F3A;4     2-Sep-79 16:56:25    EDIT BY PETERS
;<134-TENEX>DSKPAK.F3A;3     2-Sep-79 16:54:28    EDIT BY PETERS
;<134-TENEX>DSKPAK.F3A;2    30-Aug-79 19:02:56    EDIT BY PETERS
;<134-TENEX>DSKPAK.F3A;1    30-Aug-79 17:24:49    EDIT BY PETERS

;DSKPAK MODULE FOR F3A DISK DRIVES

INTERN	DSKINI,DSKRST,DSKCHK,DSKSV,DSKIO,UDSKIO,SWPTK,SWPTKH
INTERN	DIDSCI,DSKBSZ,NDSKPR,DSKPAR,CHKDSK,CHKDE1,NSECTK
INTERN	QUEBAT

EXTERN	DSKTIM,NXTDMP,FPTA,JFNOFN,SETPT,SETMPG,CPOPJ,SKPRET,DRMINI
EXTERN	PI5AC,PISC5R,DISE,DISL,EDISMS,DBUGSW,JB0FLG,NTRBAT



DSTKSZ==20			;SIZE OF DISK INTERRUPT STACK
DSKUMX==4			;MAXIMUM NUMBER OF QUEUED UDSKIO ITEMS

CMPPG==377			;MMAP SCRATCH PAGE FOR DISK DATA COMPARES
CMPPGA==CMPPG*1000		;FIRST ADDRESS IN ABOVE SAID PAGE

OPDEF DKCO[740000,,0]		;DISK CONO IOT
OPDEF DKCI[741000,,0]		;DISK CONI IOT
OPDEF DKSO[742000,,0]		;DISK CONSO IOT
OPDEF DKSZ[743000,,0]		;DISK CONSZ IOT

;BIT DEFINITIONS FOR F3A DISKS

DSKIFG==000010			;DISK INTERRUPT BIT IN RH DISK "CONI" WORD

DSKUOP==200000			;UDSKIO BIT IN LH DSKSTS
DSKXFG==100000			;MAIN XFER DONE BIT IN LH DSKSTS
				;SIGNIFICANT ONLY IF DISK COMPARES ENABLED

DSKUDN==100000			;UDSKIO DONE BIT IN LH DSKUQ1 ENTRY
DSKUER==40000			;UDSKIO ERROR BIT IN LH DSKUQ1 ENTRY
DSKULG==20000			;UDSKIO LOG BAD SPOTS IN BAT BLOCKS
DSKULA==10000			;UDSKIO LOG EVEN ASSIGNED BAD SPOTS IN BATS


;MORE PARAMETERS FOR F3A DISKS

NTRACK==NTKUN*NPACKS		;TOTAL CYLINDERS ON ALL PACKS COMBINED
MNTRCK==-NTRACK			;BECAUSE OF MACRO...
NSECPG==1000/NWSEC		;NUMBER OF SECTORS PER PAGE
NSECTK==NSURFS*NSECS		;NUMBER OF SECTORS PER CYLINDER
NPGTK==NSECTK*NWSEC/1000	;NUMBER OF PAGES PER CYLINDER
NBWTK==<NPGTK+^D35>/^D36	;NUMBER OF BIT TABLE BIT WORDS PER CYLINDER
NMINFP==NPGTK/3			;FREE CHOICE PARAMETER FOR DSKASN
DSKNST==<<<<NDST+NPGTK-1>/NPGTK>+NPACKS-1>/NPACKS>*NPACKS
				;TOTAL NUMBER OF SWAPPING CYLINDERS
				;ON ALL PACKS COMBINED
SWPTK==NTKUN/2-<DSKNST/NPACKS>/2	;FIRST SWAPPING CYLINDER
					;ON EACH PACK
SWPTKH==SWPTK+<DSKNST/NPACKS>	;ONE MORE THAN THE LAST SWAPPING
				;CYLINDER ON EACH PACK
SWPSEC==<DSKNST*NSECTK>/NPACKS	;NUMBER OF SWAPPING SECTORS PER PACK
LOTRK==0			;FIRST CYLINDER ON ALL PACKS
HITRK==NTRACK			;ONE MORE THAN THE LAST CYLINDER ON ALL PACKS
DSKBSZ==<<NTRACK+<NTRACK*NBWTK>+777>/1000>*1000	;TOTAL NUMBER OF WORDS IN
						;DISK BIT TABLE ROUNDED UP
						;TO THE NEXT FULL PAGE

DSKBTB==DSKFCT+NTRACK		;FIRST WORD OF BITS IN DISK BIT TABLE
DIDSC0==<SWPTK-1>*NSECTK	;VERY FIRST DISK ADDRESS

;STORAGE DECLARATIONS

LS DSKSRQ,NPACKS		;POINTER TO UNIT SWAP READ QUEUE
LS DSKSWQ,NPACKS		;POINTER TO UNIT SWAP WRITE QUEUE
LS DSKUWC,1			;COUNT OF WAITING UDSKIO ITEMS
LS DSKUQC,1			;COUNT OF USED UDSKIO BLOCKS
LS DSKUQ1,DSKUMX		;UDSKIO QUEUE STAUS WORD
LS DSKUQ2,DSKUMX		;UDISKIO QUEUE DISK ADR WORD
LS DSKUQ3,DSKUMX		;UDISKIO QUEUE RETURNED STATUS WORD
LS DSKACP,1			;SAVED AC P DURING DISK INTERRUPTS
LS DSKSTK,DSTKSZ		;DISK INTERRUPT STACK
LS DSKSVR,1			;DISK INTERRUPT RETURN WORD
LS DSKBLK,1			;LOCK WORD FOR DISK BIT TABLE
LS DBTJFN,1			;JFN FOR DISK BIT TABLE FILE
LS DIDSCA,1			;VERY FIRST ASSIGNED FILE DISK ADDRESS
				;ALSO XB ADR OF INDEX.;1
LS FDDSCA,1			;XB ADR OF DIRECTORY.;1
LS FILIFG,1			;FLAG TO SAY FILE SYS OK TO USE AFTER FILINI

LS DSKLUN,1			;UNIT NUMBER OF CURRENTLY ACTIVE DRIVE
				;OR -1 IF NONE

LS DSKCAW,NPACKS		;REAL CORE STARTING ADDRESS FOR CURRENT OR
				;MOST RECENT DATA TRANSFER ON THIS DRIVE
LS DSKDAW,NPACKS		;HARDWARE DISK ADDRESS FOR CURRENT OR MOST
				;OPERATION ON THIS DRIVE
LS DSKSTS,NPACKS		;SOFTWARE STATUS INFORMATION ABOUT THIS DRIVE
LS DSKCTM,NPACKS		;OVERDUE TIMER FOR THIS DRIVE
LS DSKTRY,NPACKS		;ERROR RETRY COUNTER FOR THIS DRIVE

;DISK ERROR DATA GTTAB STORAGE

LS DSKRCE,1			;TOTAL NUMBER OF RECOVERABLE DISK ERRORS
LS DSKRER,4			;DATA FROM MOST RECENT RECOVERABLE DISK ERROR
LS DSKNRE,1			;TOTAL NUMBER OF IRRECOVERABLE DISK ERRORS
LS DSKLER,4			;DATA FROM MOST RECENT IRRECOVERABLE DISK ERROR
NDSKEW==^D10			;TOTAL NUMBER OF WORDS IN THIS GTTAB TABLE

NBATEN==^D10			;LENGTH OF BAT QUEUE TABLE
LS BATEOK,1			;NONE 0 IF OK TO USE BATENQ TABLE
LS BATENQ,NBATEN		;BAT BLK ENTRY QUEUE TABLE


;LITERAL STORAGE DECLARATIONS

;DSKPAR GTTAB TABLE - USED BY CHECKDISK, SWPBAT, BLKLUK, MAYBE OTHERS

DSKPAR:	LOTRK			;0 - FIRST CYLINDER ON STRUCTURE
	HITRK			;1 - LAST CYLINDER+1 ON STRUCTURE
	NSECTK			;2 - # SECTORS / CYLINDER
	NWSEC			;3 - # WORDS / SECTOR
	NTKUN			;4 - # CYLINDERS / PACK
	NPACKS			;5 - # PACKS ON STRUCTURE
	SWPTK			;6 - 0TH SWAPPING TRACK ON A PACK
	SWPTKH			;7 - LAST + 1 SWAPPING CYLINDER ON A PACK
	NSURFS			;10 - # SURFACES OR HEADS / PACK
	NSECS			;11 - # SECTORS / TRACK (NOT PER CYLINDER)
	NSECPG			;12 - # SECTORS / PAGE
	NBWTK			;13 - # BITTABLE WORDS / CYLINDER
	DSKBSZ			;14 - SIZE OF BITTABLE (COUNT + BIT AREAS)
	NMINFP			;15 - DSKASN FREE CHOICE PARAMETER
	^-DSKMSK,,-1		;16 - MASK OF BITS IN SOFTWARE ADR
	<NUNTBT>B8+<NCYLBT>B17+<NSRFBT>B26+<NSECBT>B35 ;17 - 9 BIT HDWR SPEC
	POINT NUNTBT,0,UNTLSB	;20 - UNIT PART OF HDWR DISK ADR
	POINT NCYLBT,0,CYLLSB	;21 - CYL PART OF HDWR DISK ADR
	POINT NSRFBT,0,SRFLSB	;22 - SURFACE OR HEAD PART OF HDWR DISK ADR
	POINT NSECBT,0,SECLSB	;23 - SECTOR PART OF HDWR DISK ADR

NDSKPR==.-DSKPAR		;NUMBER OF WORDS IN THIS GTTAB TABLE

DIDSCI:	DIDSC0+DSKABT		;VERY FIRST DISK ADDRESS

;INITIALIZATION AND RESTART CODE

DSKINI:
DSKRST:	CALL DRMINI		;FIRST INIT PESUDO-DRUM STUFF
	DKCO 0			;SHUT OFF DISK INTERRUPTS
	SETOM DSKLUN		;SAY NO OPERATIONS IN PROGRESS
	SETOM DSKBLK		;UNLOCK DISK BIT TABLE
	MOVSI A,-NPACKS		;PREPARE FOR PER-UNIT INITIALIZATION LOOP
DSKRS1:	CALL DIUNIT		;DO INITIALIZATION FOR THIS UNIT
	AOBJN A,DSKRS1		;LOOP IF MORE UNITS TO INITIALIZE
	MOVSI 1,-NBATEN		;INIT BAT QUEUE TABLE
DSKRS2:	SETOM 1,BATENQ(1)	;-1 IS FREE (1B0 NOT PART OF HDWR ADR)
	AOBJN 1,DSKRS2
	AOS BATEOK		;SAY TABLE HAS BEEN INITED
	RET

DIUNIT:	RET			;DO NOTHING HERE FOR NOW...

;PERIODIC CHECK OF DISK - CALLED HERE FROM SCHEDULER PROCESS LEVEL

DSKCHK:	MOVEI A,^D1000		;DO THIS ONCE PER SECOND
	MOVEM A,DSKTIM		;SAVE FOR CLOCK ROUTINE TO USE
	MOVSI D,-NPACKS		;SET UP AOBJN LOOP TO CHECK DRIVES

DSKCH1:	SKIPN A,DSKCTM(D)	;OP PENDING ON THIS DRIVE?
	JRST DSKCH2		;NO, LOOP TO NEXT DRIVE
	SUB A,TODCLK		;SEE IF OVERDUE
	JUMPGE A,DSKCH2		;JUMP IF NOT OVER DUE YET
TIMERR:	SOSG DSKTRY(D)		;HAVE WE ALREADY LOST TOO MANY TIMES?
	BUG (HLT,<DISK OPERATION RETRIED AND OVERDUE - LOSAGE>)
	BUG(CHK,<DISK OPERATION OVERDUE>)
	PIOFF			;LOCK OUT WORLD
	DKCO DSKCHN		;SHUT OFF DISK CHANNEL AND CLEAR FLAG
	CALL RECAL		;FIRST RECALIBRATE
	MOVE A,DSKCAW(D)	;GET BACK CORE ADDRESS
	MOVE B,DSKDAW(D)	;AND DISK ADDRESS
	CALL DSKXFR		;GO INIT XFER
	PION			;TURN INTERRUPTS BACK ON

DSKCH2:	AOBJN D,DSKCH1		;LOOP TO NEXT UNIT IF MORE
	RET


CHKDSK: JFCL			;FALL THRU TO BAT STUFF

;CALLED BY JOB 0 TO MAKE ANY BAT ENTRIES NECESSARY

DSKJB0:	SKIPN BATEOK		;OK TO USE BATENQ?
	 RET			;NO-NOT INITED YET
	MOVSI 1,-NBATEN		;NOW CHK BAT ENTRY Q TABLE
DSKJB1:	MOVE 2,BATENQ(1)	;GET IT
	CAME 2,[-1]		;FREE?
	 CALL DSKBAT		;NO-DO IT
	SETOM 1,BATENQ(1)	;SAY ITS FREE NOW
	AOBJN 1,DSKJB1		;LOOP FOR ALL OF TABLE
	RET

;HERE WITH BATENQ INDEX IN 1, THE ENTRY ITSELF IN 2

DSKBAT:	PUSH P,1		;SAVE AOBJN PTR
	PUSH P,2		;SAVE ENTRY
	MOVE 1,2		;GET HDWR DISK ADR & FLAG IN 1
	CALL NTRBAT		;ENTER INTO BAT BLOCK
	 JRST [	HRROI 1,[ASCIZ/
[Job 0 FAILED to make auto BAT block entry for (HDWR fmt): /]
		JRST DSKBA1]
	HRROI 1,[ASCIZ/
[Job 0 made auto BAT block entry for (HDWR fmt): /]
DSKBA1:	PSOUT
	MOVEI 1,101
	MOVE 2,(P)
	TLZ 2,(1B0)		;CLEAR POSSIBLE FLAG
	MOVEI 3,10
	NOUT
	 JFCL
	HRROI 1,[ASCIZ/]
/]
	PSOUT
	POP P,2
	POP P,1
	RET			;RET TO DOOP, FAKE READ OK


CHKDE1:	RET

;INTERRUPT SERVICE ROUTINE FOR F3A DISKS

DSKSV:	XWD DSKSVR,.+1		;JSYS HERE FROM PISRV
	DKCI 0			;COLLECT CONI STATUS
	TRNN 0,DSKIFG		;IS THIS INTERRUPT FOR US?
	JRST @DSKSVR		;NOTA...
	DKCO 0			;CLEAR FLAG AND ZERO OUT CHANNEL
	SKIPGE D,DSKLUN		;WERE WE WAITING FOR SOMETHING TO HAPPEN?
	JRST @DSKSVR		;NOTA...
	MOVEM P,DSKACP		;SAVE AC P
	MOVE P,[IOWD DSTKSZ,DSKSTK]	;ESTABLISH CONTEXT
	RC 0			;GET HARDWARE STATUS BITS
	TRNE 0,S.ANY		;ANY "NORMAL" ERROR OCCUR?
ANYERR:	JRST DSKSER		;YES, GO RETRY
	TLNE 0,S.IPE		;INTERNAL PARITY ERROR?
IPEERR:	JSP A,DSKDER		;YES, GO RETRY
	RM 0			;GET ENDING MA PLUS ONE
	SUB 0,MA		;MINUS STARTING ADDRESS
	HRRZS 0			;FLUSH GARBAGE BITS
	CAIE 0,1000		;BETTER BE ONE THOUSAND EXACTLY...
RMAERR:	JSP A,DSKDER		;ELSE DATA XFER LOST...
	MOVSI A,DSKXFG		;SEE IF THIS IS A COMPARE XFER FINISHING
	TDNN A,DSKSTS(D)	;IS IT?
	JRST DSKSCC		;NO, GO SEE IF ONE IS NEEDED
	ANDCAM A,DSKSTS(D)	;YES, SHUT OFF COMPARE XFER DONE IN CASE LOSE
	CALL DSKCMP		;GO DO DATA COMPARE
	JRST DSKSE1		;DATA COMPARE LOSSAGE, GO RE-DO EVERYTHING
	JRST DSKSVD		;ALL OK, GO MARK XFER COMPLETE

DSKSCC:	MOVSI A,DWRBIT		;PREPARE TO CHECK IF READ OR WRITE
	TDNE A,DSKSTS(D)	;SKIP IF READ
	JRST DSKSCW		;WRITE...
	SKIPN DSKRCF		;READ, ARE WE DOING READ COMPARES?
	JRST DSKSVD		;NO, GO MARK XFER COMPLETED

DSKSCX:	MOVSI A,DSKXFG		;YES
	IORM A,DSKSTS(D)	;SO MARK MAIN XFER COMPLETE
	MOVE A,DSKCAW(D)	;RESTORE MA
	MOVE B,DSKDAW(D)	;AND DA
	CALL DSKXFR		;AND GO INIT COMPARE XFER
	JRST DSKINR		;THEN DEBREAK

DSKSCW:	SKIPE DSKWCF		;WRITE, ARE WE DOING WRITE COMPARES?
	JRST DSKSCX		;YES, GO START IT UP

DSKSVD:	MOVE A,DSKSTS(D)	;GET STATUS FOR THAT UNIT
	SETZM DSKCTM(D)		;ZERO OUT OVERDUE TIMER
	TLNE A,DSKUOP		;WAS THIS A UDSKIO ENTRY?
	JRST DSKSVU		;YES, GO SET DONE BIT
	JSP D,SWPDON		;NO, NOTIFY SWAPPER
	JRST DSKSVS		;GO UNLOCK AND DO ANOTHER XFER IF NEEDED

DSKSVU:	MOVSS A			;GET UDSKIO BLOCK INDEX
	ANDI A,777		;FLUSH NON-INDEX BITS
	MOVSI B,DSKUDN		;UDSKIO DONE BIT
	IORM B,DSKUQ1(A)	;TURN IT ON IN BLOCK
	MOVEM 0,DSKUQ3(A)	;AND SAVE RETURNED STATUS BITS
	SOS DSKUWC		;DECREMENT COUNT OF WAITING UDSKIO XFERS

DSKSVS:	SETOM DSKLUN		;SAY DISK NOW FREE FOR NEXT USE
	CALL DSKDOP		;THEN GO CHECK FOR ANY NEW STARTUPS NEEDED

DSKINR:	MOVE P,DSKACP		;RESTORE PREVIOUS CONTEXT
	MOVSI D,PI5AC		;AND BLT BACK LOW ACS
	BLT D,D			;SAVED BY PISRV
	JEN @PISC5R		;DEBREAK

DSKCMP:	MOVEI A,DSKWBF		;IF IT WAS A WRITE, WE DON'T HAVE TO MAP
	SETZ 0,			;CLEAR ERROR FLAG
	MOVSI C,-1000		;SET UP COMPARE LOOP COUNT
	MOVSI B,DWRBIT		;CHECK WRITE BIT
	TDNE B,DSKSTS(D)	;WRITE?
	JRST DSKCLP		;YES, JUST GO DO COMPARE
	MOVE A,DSKCAW(D)	;READ, MUST DO MAP MADNESS
	LSH A,-^D9		;MAKE CPN OUT OF MA
	PUSH P,CST0(A)		;SAVE PAGE STATE
	PUSH P,A		;SAVE CPN
	HRLI A,RWX!ACCESB	;MAKE MAP WORD OUT OF CPN
	MOVEM A,MMAP+CMPPG	;INSTALL IN MMAP
	MOVSI B,100000		;PREPARE REASONABLE AGE
	MOVEM B,CST0(A)		;INSTALL IN PAGE STATE
	CONO PGR,1		;CLEAR EXEC ARS
	MOVEI A,CMPPGA		;POINT COMPARER TO WRITE BUFFER

DSKCLP:	MOVE B,DSKRBF(C)	;GET A READ COMPARE WORD
	CAME B,0(A)		;BETTER BE THE SAME AS ORIGINAL DATA
CMPERR:	ADDI 0,1		;ELSE ADD ONE TO ERROR COUNT
	ADDI A,1		;INCREMENT WORD COUNT
	AOBJN C,DSKCLP		;LOOP IF MORE WORDS TO COMPARE
	MOVSI A,DWRBIT		;NOW CHECK IF READ OR WRITE
	TDNE A,DSKSTS(D)	;READ?
	JRST CMPRET		;NO, JUST CHECK STATE AND RETURN
	POP P,A			;YES, GET BACK CPN
	POP P,CST0(A)		;RESTORE PAGE STATE
	SETZM MMAP+CMPPG	;CLEAR GARBAGE MMAP WORD
	CONO PGR,1		;CLEAR EXEC MAP

CMPRET:	CAIN 0,0		;ANY ERRORS SEEN?
	AOS 0(P)		;NO, TAKE SKIP RETURN
	RET

;HERE ONLY FROM DSKSV

DSKSER:	SOSG DSKTRY(D)		;HAVE WE LOST TOO MANY TIMES?
	 JRST EFANCY		;DO FANCY ERROR PROCESSING
	JRST DSKSE2		;NO

;HERE FROM OTHER PLACES

DSKSE1:	SOSG DSKTRY(4)
	 JSP A,DSKERR
DSKSE2:	TLNE 0,S.SKER		;SEEK ERROR?
SEKERR:	CALL RECAL		;YES, RECALIBRATE BEFORE RETRY
	MOVE A,DSKCAW(D)	;RE-DO MAIN XFER
	MOVE B,DSKDAW(D)	;RESTORE NEEDED DISK ADDRESS
	CALL DSKXFR		;GO INIT XFER
	JRST DSKINR		;AND GO BACK TO PISRV

DSKDER:	MOVSI B,DWRBIT		;PREPARE TO SEE IF READ OR WRITE
	TDNE B,DSKSTS(D)	;SKIP IF READ
	JRST DSKDEW		;WRITE
	SKIPE DSKRCF		;SKIP IF WE ARE NOT DOING READ COMPARES
	JRST 0(A)		;WE ARE, RETURN TO DO COMPARE
	JRST DSKSE1		;WE AREN'T, GO TRY AGAIN

DSKDEW:	SKIPE DSKWCF		;SKIP IF WE ARE NOT DOING WRITE COMPARES
	JRST 0(A)		;WE ARE, RETURN TO DO COMPARE
	JRST DSKSE1		;WE AREN'T, GO TRY AGAIN

;HERE VIA JSP A,

DSKERR:	BUG (HLT,<DSKERR: UNRECOVERABLE DISK ERROR, PC IN 1>)
	JRST DSKERR		;MUST $G AWAY

;FANCY DISK ERROR HANDLING AT PI LEVEL
;WE ONLY GET HERE VIA A JRST FROM DSKSER

;TO WIN IN THIS STUFF FOR BAD SPOTS:
; MUST BE READ OPERATION THAT FAILED
; MUST NOT BE DOING READ COMPARES

;STATUS BITS IN 0
;DRIVE INDEX IN 4

EFANCY:	PUSH P,1		;CLOBBER NO ACS AT PI LEVEL
	PUSH P,2
	PUSH P,3
	MOVE 1,DSKSTS(4)
	TLNN 1,DWRBIT		;WRITE? (ASSUME NO BAD SPOT WRITES DETECTED)
	SKIPE DSKRCF		;OR DOING READ COMPARES?
	 JRST EFANCX		;YES-DON'T GET TANGLED UP
	CALL EBADSP		;IS ERROR CLASSIFIED AS A BAD SPOT?
	 JRST EFANCX		;NOT A BAD SPOT - DIE
	TLNN 1,DSKUOP		;UDSKIO READ?
 	 JRST ESWPIN		;NO-SWAP READ
EUDSKI:	LDB 1,[POINT ^D9,DSKSTS(4),^D17] ;GET DSKUQ_ INDEX FROM DSKSTS
	MOVSI 2,DSKUER		;PASS ERROR BIT
	IORB 2,DSKUQ1(1)	;INTO UDSKIO Q
	TLNN 2,DSKULG		;WANT TO LOG BAD SPOTS IN BATS?
	 JRST ERETRN		;NO-DONE
	MOVE 1,DA		;THE DISK ADR OF CONCERN
	TLZ 1,(1B0)		;ASSUME NO BAT ENTRY FOR ASSIGNED DISK ADR
	TLNE 2,DSKULA		;BUT WANT THEM?
	 TLO 1,(1B0)		;YES-TELL QUEBAT ABOUT IT
	CALL QUEBAT		;QUEUE FOR JOB 0 BAT BLK ENTRY
	 JRST EFANCZ		;FAILED
ERETRN:	POP P,3
	POP P,2
	POP P,1
	JRST DSKSVD		;FAKE OK READ, USER SHOULD SEE ERROR BITS


;HERE WHEN READ ERROR WAS OF SWAPPING TYPE.

ESWPIN:	MOVE 1,DSKCAW(4)	;GET RCA FOR LOSING TRANSFER
	LSH 1,-^D9		;MAKE CPN
	MOVSI 2,SWPERR		;ERROR BIT
	IORM 2,CST3(1)		;INTO PLACE, ACTION WILL BE TAKEN IN SWPDON
	MOVE 1,DA		;THE DISK ADR OF CONCERN
	TLO 1,(1B0)		;SAY WANT BAT ENTRY EVEN FOR ASSIGNED ADR
	CALL QUEBAT		;QUEUE FOR JOB 0 BAT BLK ENTRY
	 JRST EFANCZ		;FAILED
	JRST ERETRN		;OK, SWPDON WILL MARK XB AS PTING TO BAD SPOT
				;OR FIX UP DRUM ADR


;CALL THIS TO DETERMINE IF DISK ERROR IS DUE TO BAD SPOT (ECC ERR FOR NOW)
;SKIPS FOR BAD SPOTS

EBADSP:	TLNE 0,(1B6!1B9!1B10)	;ECC ERRORS ARE BAD SPOTS FOR NOW
	 AOS (P)
	RET


;CALLED AT DISK PI LEVEL OR BY PROCESS (DOES PIOFF FOR LOCKING OF QUEUE)
;CALL THIS TO QUEUE DISK ADR FOR ENTRY INTO BAT BLKS BY JOB 0
;ACCEPTS 1/ DISK ADR ! 1B0 TO FORCE BAT ENTRY EVEN IF DSK ADR IS ASSIGNED
;SKIPS FOR SUCCESS.
;AN ENTRY IS XB0!DA WHERE X IS 1 TO FORCE BAT ENTRY EVEN FOR ASSIGNED ADRS

QUEBAT:	MOVSI 3,-NBATEN		;LOOK FOR ROOM
	PIOFF			;LOCK UP
QUEBA1:	MOVE 2,BATENQ(3)	;GET ENTRY
	CAMN 2,[-1]		;FREE?
	 JRST QUEBA2		;YES
	AOBJN 3,QUEBA1		;LOOK AT EM ALL
	PION			;RESTORE PI
	 RET			;NO ROOM

QUEBA2:	MOVEM 1,BATENQ(3)	;Q IT, DSKCHK WILL HANDLE IT
	PION			;RESTORE PI
	AOS JB0FLG		;GET JOB 0 TO DO THE WORK
	AOS (P)
	RET


;HERE WHEN SOMETHING NOT RIGHT.

EFANCX:	POP P,3			;RESTORE ACS
	POP P,2
	POP P,1
	JSP A,DSKERR		;JUST AS DSKSER WOULD HAVE

;HERE WHEN QUEBAT FAILS ABOVE

EFANCZ:	BUG (CHK,<EFANCY: FAILED TO QUEUE BAT ENTRY FOR JOB 0>)
	JRST EFANCX



;DISK I/O DRIVER, FIRST TYPE - CALLED FROM SWAPPER ONLY WITH
;CORE PAGE NUMBER IN AC A - B0 OFF=READ, B0 ON=WRITE

DSKIO:	PUSH P,A		;PRESERVE DWRBIT AND CPN AGAINST CLOBBERAGE
	MOVEI B,CST3(A)		;MAKE A POINTER TO THIS ENTRY
	MOVEI C,DSKSRQ		;POINT TO READ QUEUE
	TLNE A,DWRBIT		;UNLESS A WRITE IS REQUESTED
	MOVEI C,DSKSWQ		;THEN POINT TO WRITE QUEUE
	PIOFF			;MUST NOT INTERRUPT QUEUEING
	EXCH B,0(C)		;INSTALL POINTER TO NEW ENTRY
	HLL B,A			;INSTALL DWRBIT FOR THIS ENTRY
	MOVEM B,CST3(A)		;FINISH QUEUE SETUP
	PION			;OK TO INTERRUPT NOW
	SKIPGE DSKLUN		;ANYTHING HAPPENING NOW?
	CALL DSKDOP		;NO, GO TRY TO START IT UP
	POP P,A			;RETURN DWRBIT AND CPN TO CALLER
	RET

;DISK I/O DRIVER, SECOND TYPE - CALLED FOR ALL DISK ACCESS EXCEPT
;FROM WITHIN THE SWAPPER WITH HARDWARE DISK ADDRESS IN AC A, WORD COUNT
;AND B14 OFF=READ, B14 ON=WRITE IN AC B, REAL CORE ADDRESS IN AC C
;WORD COUNT IS IGNORED (ALWAYS 1000 OCTAL) AND REAL CORE ADDRESS IS FORCED
;TO BE AT THE START OF A PAGE BOUNDRY
;AC2/ 1B0 => LOG BAD SPOTSIN BAT BLOCKS, 1B1 => LOG EVEN ASSIGNED SPOTS IN BATS

UDSKIO:	PUSH P,A		;SAVE HARDWARE DISK ADDRESS
	
UDSKI1:	PIOFF			;LOCK OUT WORLD BEFORE QUEUEING ITEM
	MOVEI A,DSKUMX		;MAXIMUM ALLOWED DSKUQ_ ITEMS
	CAMLE A,DSKUQC		;ALREADY FULL?
	JRST UDSKI2		;NO, GO QUEUE ITEM
	PION			;FULL, TURN INTERRUPTS BACK ON
	MOVEI A,DUQTST		;PREPARE TO WAIT FOR FREE ENTRY
	JSYS EDISMS		;SLEEP UNTIL SPACE AVAILABLE
	JRST UDSKI1		;TRY, TRY, TRY AGAIN

UDSKI2:	MOVSI A,-DSKUMX		;PREPARE AOBJN TO FIND FREE BLOCK

UDSKI3:	SKIPN DSKUQ1(A)		;THIS BLOCK FREE?
	JRST UDSKI4		;YES, GO SET IT UP
	AOBJN A,UDSKI3		;GO CHECK NEXT BLOCK
	BUG(HLT,<UDSKIO: IMPOSSIBLE FAILURE TO FIND FREE BLOCK>)
	JRST PINRET		;TURN ON INTERRUPTS AND RETURN

UDSKI4:	LSH C,-^D9		;MAKE CPN OUT OF RCA
	HRLI C,DSKUOP(A)	;INSTALL UDSKIO BIT AND BLOCK INDEX
	TLNE B,10		;WRITE?
	 TLO C,DWRBIT		;YES
	TLNE B,(1B0)		;LOG BAD SPOTS IN BAT BLOCKS?
	 TLO C,DSKULG		;YES
	TLNE B,(1B1)		;EVEN ASSIGNED IN FILESYSTEM BAD SPOTS?
	 TLO C,DSKULA		;YES
	MOVEM C,DSKUQ1(A)	;PUT FIRST WORD IN BLOCK
	POP P,DSKUQ2(A)		;RESTORE HARDWARE DISK ADDRESS TO BLOCK
	AOS DSKUQC		;ONE MORE UDSKIO BLOCK USED
	AOS DSKUWC		;ONE MORE WAITING REQUEST
	PION			;OK TO INTERRUPT NOW
	PUSH P,A		;SAVE INDEX FOR ZEROING ENTRY
	SKIPGE DSKLUN		;DISK NOW FREE?
	CALL DSKDOP		;YES, GO START SOMETHING
	MOVE A,0(P)		;GET INDEX FOR WAIT TEST
	HRLI A,DXFTST		;PREPARE TO WAIT FOR ITEM TO BE DONE
	MOVSS A			;DATA,,WAIT-TEST FOR EDISMS
	JSYS EDISMS		;WAIT UNTIL UDSKIO DONE BIT SETS
	POP P,B			;RESTORE INDEX
	MOVE C,DSKUQ1(B)	;GET STATUS BITS FROM Q ENTRY
	SETZ A,			;INIT ERROR BITS TO NONE
	TLNE C,DSKUER		;ERROR BIT SET IN Q ENTRY?
	 MOVE A,DSKUQ3(B)	;ERROR, RETURN SAVED STATUS BITS

	PIOFF			;SHUT OUT WORLD WHILE UNQUEUEING

	SETZM DSKUQ1(B)		;ZERO BITS AND CPN
	SETZM DSKUQ2(B)		;AND ALSO HARDWARE DISK ADDRESS
	SETZM DSKUQ3(B)		;AND RETURNED STATUS BITS
	SOS DSKUQC		;AND DECREMENT USED COUNT

PINRET:	PION			;TURN ON INTERRUPTS
	RET

DUQTST:	MOVEI A,DSKUMX		;MAXIMUM NUMBER OF UDSKIO BLOCKS
	CAMG A,DSKUQC		;STRICTLY GREATER THAN CURRENT COUNT?
	JRST 0(D)		;NO, KEEP WAITING
	JRST 1(D)		;YES, OK TO QUEUE NOW

DXFTST:	MOVSI B,DSKUDN		;UDSKIO DONE BIT
	TDNN B,DSKUQ1(A)	;XFER COMPLETED?
	JRST 0(D)		;NO, KEEP WAITING
	JRST 1(D)		;YES, RESTART PROCESS

;HERE WE SIMPLY MAKE VERY SURE THE DISK IS FREE AND THEN UNQUEUE
;AN OPERATION FOR STARTUP IF IT REALLY IS OR DO NOTHING IF IT ISN'T

DSKDOP:	PIOFF			;FREEZE WORLD BEFORE CHECKING THINGS
	SKIPL DSKLUN		;DISK WILL PROBABLY BE FREE HERE
	JRST PINRET		;BUT JUST RETURN IF NOT
	SKIPE DSKUWC		;UDSKIO REQUESTS WAITING?
	JRST DSKDO3		;YES, DO THEM FIRST
	CALL UNQSRD		;NO, ANY SWAP READS TO DO?
	JRST DSKDO1		;NO, GO CHECK FOR SWAP WRITES
	JRST DSKDO2		;YES, GO DO IT

DSKDO1:	CALL UNQSWR		;NO, ANY SWAP WRITES WAITING?
	JRST PINRET		;NOTHING TO DO, JUST RETURN

DSKDO2:	PUSH P,A		;SAVE DWRBIT AND CPN
	MOVE A,CST1(A)		;GET BACKUP ADDRESS FOR THIS PAGE
	TLNN A,(DSKABT)		;REGULAR DISK ADDRESS?
	CALL CVSWAD		;NO, CONVERT SWAP ADDRESS
	CALL CVDSK		;NOW CONVERT TO HARDWARE ADDRESS, EITHER WAY
	MOVE B,A		;MOVE DISK ADDRESS TO B AS IN UDSKIO CASE
	POP P,A			;RESTORE DWRBIT AND CPN
	JRST DSKDO7		;GO SET UP PHYSICAL XFER

DSKDO3:	MOVSI B,-DSKUMX		;PREPARE TO FIND A UDSKIO ITEM

DSKDO4:	SKIPN A,DSKUQ1(B)	;THIS BLOCK IN USE?
	JRST DSKDO5		;NO, GO CHECK NEXT
	TLNN A,DSKXFG		;YES, IS XFER ALREADY COMPLETED?
	JRST DSKDO6		;NO, GO START IT UP

DSKDO5:	AOBJN B,DSKDO4		;GO CHECK NEXT BLOCK
	BUG(HLT,<DSKDOP: IMPOSSIBLE FAILURE TO FIND DSKUQ_ ENTRY>)
	JRST PINRET		;TURN ON PI AND RETURN

DSKDO6:	MOVE B,DSKUQ2(B)	;GET DISK ADDRESS AND FALL THROUGH

DSKDO7:	LDB D,[POINT NUNTBT,B,<^D35-NCYLBT-NSRFBT-NSECBT>]
	MOVEM D,DSKLUN		;INSTALL REAL UNIT IN DSKLUN
	MOVEM A,DSKSTS(D)	;INSTALL NEEDED INFO IN DSKSTS
	HRRZS A			;FLUSH STATUS BITS
	LSH A,^D9		;NOW CONVERT CPN TO RCA
	MOVEM A,DSKCAW(D)	;SAVE AWAY CORE ADDRESS OF XFER PER DRIVE
	MOVEM B,DSKDAW(D)	;LAST DISK ADDRESS OF XFER PER DRIVE
	MOVEI C,^D1000		;RETRY ONE THOUSAND TIMES BEFORE GIVING UP
	MOVEM C,DSKTRY(D)	;INIT RETRY COUNTER AS SUCH
	CALL DSKXFR		;GO INIT XFER
	JRST PINRET		;TURN ON INTERRUPTS AND RETURN

;HERE TO PROCESS A SWAP READ QUEUE
;CALL: QUEUE TO SEARCH IN AC A
;RETURN: +1 IF NO ITEM FOUND, +2 WITH CPN OF ITEM IN AC A

UNQSRD:	MOVEI A,DSKSRQ		;ONLY ONE QUEUE TO LOOK AT FOR NOW...
	SKIPN B,0(A)		;SKIP IF ANY ITEMS ON QUEUE, LOAD FIRST
	RET			;ITEM POINTER, ELSE SAY NONE FOUND

UNQSRL:	HRRZ C,0(B)		;GET RH OF ITEM TO AC C
	JUMPE C,UNQSRQ		;GO UNQUEUE IF END
	MOVE A,B		;ELSE MOVE POINTER TO POINTER-POINTER
	MOVE B,C		;AND ITEM TO POINTER
	JRST UNQSRL		;THEN GO CHECK NEXT ITEM

UNQSRQ:	HLLZS 0(A)		;ZERO POINTER, THUS UNQUEUEING ITEM
	SKIPGE 0(B)		;MAKE SURE ITEM IS A READ, ELSE DIE
	BUG(HLT,<WRITE REQUEST FOUND ON SWAP READ QUEUE>)
	MOVEI A,-CST3(B)	;RETURN CPN IN AC A
	AOS 0(P)		;TAKE SKIP RETURN
	RET

;HERE TO PROCESS A SWAP WRITE QUEUE
;CALL: QUEUE TO SEARCH IN AC A
;RETURN: +1 IF NO ITEM FOUND, +2 WITH DWRBIT,,CPN OF ITEM IN AC A

UNQSWR:	PUSH P,E		;SAVE AC E WHICH WE MAY CLOBBER
	MOVEI B,DSKSWQ		;ONLY ONE QUEUE TO LOOK AT FOR NOW...

UNQSWL:	HRRZ C,0(B)		;GET POINTER TO ITEM
	JUMPE C,UNQSWQ		;GO TRY TO UNQUEUE AN ITEM IF END
	MOVEI A,-CST3(C)	;MAKE ITEM CPN OUT OF POINTER
	MOVSI D,700000		;PREPARE TO CHECK AGE FIELD
	TDNN D,CST0(A)		;HAS PAGE BEEN TOUCHED SINCE BEING QUEUED?
	JRST UNQSWD		;NO, UPDATE CONTEXT AND LOOP TO NEXT ITEM
	MOVSI D,(CORMB)		;YES, MAKE SURE CORE MODIFIED BIT IS SET
	IORM D,CST0(A)		;IN CST0 ENTRY OF ITEM BEFORE DELETING
	HRRZ D,0(C)		;PUT POINTER TO ITEM-NEXT
	HRRM D,0(B)		;IN POINTER TO ITEM-THIS, THUS UNQUEUING ITEM
	PUSH P,B		;SAVE POINTER-POINTER AGAINST SWPDON
	JSP D,SWPDON		;CLEAR IO REQUEST IN SWAPPER
	POP P,B			;RESTORE POINTER-POINTER
	JRST UNQSWL		;LOOP TO NEXT ITEM

UNQSWD:	MOVE E,B		;SAVE OLD POINTER-POINTER
	MOVE B,C		;OVERWRITE OLD POINTER-POINTER WITH NEW
	JRST UNQSWL		;LOOP TO NEXT ITEM

UNQSWQ:	MOVE A,E		;PRESERVE SAVED POINTER-POINTER IF ANY
	POP P,E			;RESTORE SAVED AC E
	CAIN B,DSKSWQ		;ANY ITEMS NOW IN QUEUE?
	RET			;NO, JUST RETURN
	HLLZS 0(A)		;YES, UNQUEUE
	SKIPL 0(B)		;MAKE SURE ITEM IS A WRITE, ELSE DIE
	BUG(HLT,<READ REQUEST FOUND ON SWAP WRITE QUEUE>)
	MOVEI A,-CST3(B)	;RETURN CPN IN AC A
	HRLI A,DWRBIT		;INSTALL DWRBIT
	AOS 0(P)		;TAKE SKIP RETURN
	RET

;HERE TO ACTUALLY START AN XFER - CALLED FROM PROCESS AND INTERRUPT
;LEVEL - A: DWRBIT,,CPN  B: HDW DISK ADDR  D: UNIT

DSKXFR:	MOVSI C,DWRBIT		;PREPARE TO CHECK FOR READ
	TDNE C,DSKSTS(D)	;IS IT?
	JRST DSKXWR		;NO, GO TO WRITE CODE
	SKIPE DSKRCF		;ARE WE DOING READ COMPARES?
	JRST DSKXRC		;YES, BRANCH TO DIFFERENT CODE
	CALL DREAD		;NO, JUST DO THE READ
	JRST DSKXRT		;NOW UPDATE TIMER AND RETURN

DSKXRC:	MOVSI C,DSKXFG		;PREPARE TO SEE IF MAIN XFER OR COMPARE READ
	TDNE C,DSKSTS(D)	;SKIP IF MAIN XFER NOT DONE YET

DSKXRR:	MOVEI A,DSKRBF		;COMPARE READ GOES TO READ COMPARE BUFFER
	CALL DREAD		;START IT UP
	JRST DSKXRT		;NOW RESET TIMER AND RETURN

DSKXWR:	SKIPE DSKWCF		;ARE WE DOING WRITE COMPARES?
	JRST DSKXWC		;YES, BRANCH TO DIFFERENT CODE
	CALL DWRITE		;NO, JUST START IT UP
	JRST DSKXRT		;NOW UPDATE TIMER AND RETURN

DSKXWC:	MOVSI C,DSKXFG		;PREPARE TO SEE IF MAIN XFER OR COMPARE READ
	TDNE C,DSKSTS(D)	;SKIP IF MAIN XFER NOT DONE YET
	JRST DSKXRR		;MAIN XFER DONE, GO DO COMPARE READ
	LSH A,-^D9		;MAKE MA INTO CPN
	PUSH P,CST0(A)		;SAVE PAGE STATE
	MOVSI C,100000		;INSTALL REASONABLE AGE
	MOVEM C,CST0(A)		;IN PAGE STATE WORD
	HRLI A,RWX!ACCESB	;MAKE A NICE PRIVATE PAGE POINTER
	MOVEM A,MMAP+CMPPG	;INSTALL IT IN MMAP
	CONO PGR,1		;CLEAR EXEC ARS HERE
	MOVE C,[CMPPGA,,DSKWBF]	;PREPARE FOR BLT
	BLT C,DSKWBF+777	;TO WRITE BUFFER
	SETZM MMAP+CMPPG		;CLEAR GARBAGE MMAP WORD
	POP P,CST0(A)		;RESTORE PAGE STATE
	CONO PGR,1		;RE-CLEAR EXEC MAP
	MOVEI A,DSKWBF		;POINT TO WRITE BUFFER
	CALL DWRITE		;NOW GO START IT UP

DSKXRT:	MOVE A,TODCLK		;GET CURRENT TIME
	ADDI A,^D1000		;GEVE IT ONE SECOND
	MOVEM A,DSKCTM(D)	;SAVE FOR OVERDUE CHECK
	DKCO DSKCHN		;MAKE SURE DISK HAS CHANNEL
	RET

DSKRCF:	0			;FLAG TO SAY DO READ COMPARES
DSKWCF:	0			;FLAG TO SAY DO WRITE COMPARES


;DEFINE REGISTERS PDL,A,B SOMEWHERE

;CALL:	MOVE A,[<MEMORY STARTING ADDRESS>]
;	MOVE B,[BYTE(6)UNIT(13)CYLINDER(8)HEAD(8)SECTOR]
;	PUSHJ PDL,<DWRITE OR DREAD>
;	<RETURNS ON SUCCESS, HALTS AT DERROR ON ERROR>
;	  <AT DERROR, REG. 0 HAS ERROR BITS IN IT.>
;CLOBBERS A,B,C

INTERNAL DWRITE,DREAD


;DEFS. OF TEMP. IOTS

OPDEF LA[723000,,0]
OPDEF RA[717000,,0]
OPDEF LC[721000,,0]
OPDEF RC[715000,,0]
OPDEF LE[724000,,0]
OPDEF LM[722000,,0]
OPDEF RM[716000,,0]


LS DA,1
LS MA,1
LS CMD,1
LS RCNT,1
LS ERRBIT,1
LS DINTFG,1


		;RIGHT HALF ERROR BITS
S.ANY==200
S.NACT==20
		;LEFT HALF BITS
S.NBSY==1000
S.SERR==400000
S.IPE==10	;INTERNAL PARITY ERROR
S.OVRN==40	;DATA OVERRUN
S.WRP==200000	;UNIT IS WRITE PROTECTED
S.NRDY==100000	;UNIT NOT READY
S.SKER==20000	;SEEK ERROR (CODE BELOW DOES AUTO. RECALIBRATE)
S.FALT==10000	;UNIT FAULT

DREAD:	TDZA C,C		;READ COMMAND IS ALL ZERO.

DWRITE:	MOVEI C,11000		;WRITE COMMAND.
	PUSH P,0		;0 USED AS TEMP. BELOW
	MOVEM B,DA		;SAVE DISK ADDRESS
	CALL DOOP		;DO THE OPERATION.
	POP P,0
	RET

DOOP:	MOVEM A,MA		;RECORD THE DATA ADDRESS.
	MOVEM C,CMD		;ALSO THE COMMAND.
	MOVEI 10		;RETRY COUNT
	MOVEM RCNT
	LE [2]			;RESET CTRL
DOOP1:	MOVE 1,DA		;GET DISK ADDRESS
	LA 1			;DESELECT
	TLO 1,2000		;INSTALL SELECT ENABLE BIT
	LA 1			;SELECT DRIVE AND LOAD DSK ADR.
	RC 0			;READ STATUS BITS.
	TLNE S.SERR		;SELECT ERROR ?
B.SERR:	JSP B,B.ERR
	MOVEI A,404000		;GIVE CLEAR FAULT COMMAND.
	SETZM DINTFG		;TELL GO TO WAIT FOR COMPLETION
	CALL GO
	JSP B,B.ERR		;TIMEOUT RETURN
	MOVE A,CMD		;NOW GIVE MAIN COMMAND.
	LM MA			;LOAD THE MEMORY ADDRESS.
	RC 0
	TLNN S.NRDY		;BETTER STILL BE READY...
	TRNE S.ANY		;...NO ERRORS SHOULD HAVE APPEARED...
R.ANY:	JSP B,B.ERR
	SETOM DINTFG		;TELL GO TO RETURN IMMEDIATELY
	CALL GO
	JRST [	CALL RECAL	;RECALIBRATE IF TIMEOUT
		JRST ERR1]	;THEN GO RETRY IF NOT TOO MANY ERRORS
	TLNN S.IPE		;INTERNAL PARITY ERROR ?
	TRNE S.ANY		;ANY OTHER ERROR ?
G.ANY:	JSP B,B.ERR
DOOPX:	RET

GO:	LE [2]			;INIT THE CONTROLLER.
	LC A			;SEND THE COMMAND.
	LE [1]			;START THE CONTROLLER.
	SKIPE DINTFG		;ARE WE TO WAIT FOR COMPLETION?
	JRST SKPRET		;NO, RETURN IMMEDIATELY
	MOVEI A,60000		;TIMEOUT DELAY
GOL:	RC 0
	IMULI 4,1		;STOP USING MEMORY FOR A WHILE.
	TRNN S.NACT		;CHECK FOR ACTIVE
	SOJG A,GOL
	JUMPLE A,.+2		;CHECK FOR TIMED OUT...
	AOS (P)			;SKIP RETURN IF NO ERROR...
	RET

B.ERR:	SUBI B,1
	TLNE S.SERR		;SELECT ERROR ?
	 JSP A,DERROR		;DIE !
	TLNE S.SKER		;SEEK ERROR ?
	CALL RECAL		;YES, RECALIBRATE
ERR1:	SOSG RCNT		;HAVE WE RETRIED ENOUGH ?
	 JSP A,DERROR		;YES.
	JRST DOOP1		;TRY, TRY, TRY AGAIN...

RECAL:	MOVE A,[1404000]	;RECALIBRATE
	SETZM DINTFG		;TELL GO TO WAIT FOR COMPLETION
	CALL GO
	 JSP A,DERROR		;DIE IF THIS TIMES OUT
	TRNE S.ANY
	 JSP A,DERROR		;OR IF ANY ERROR OCCURED
	RET

DERROR:	BUG(HLT,<IRRECOVERABLE DISK ERROR>)
	JRST DERROR

END

